(define (string-split-by-string input separator)
  ;; base case, the string is exhausted
  (cond [(= (string-length input) 0) '()]
        [else
         (let ([pos-of-separator (string-contains input separator)])
           (cond
            ;; if there is another separator in the string
            [pos-of-separator
             ;; we need to cut out the prefix until that string and
             ;; recur
             (let ([prefix (substring input 0 pos-of-separator)]
                   [suffix (substring input (+ pos-of-separator (string-length separator)))])
               (cons prefix
                     (string-split-by-string suffix separator)))]
            ;; if there is no occurrence of separator in the input
            ;; string
            [else (cons input '())]))]))

(define (string-repeat str n)
  (define (iter port str n)
    (cond
     [(> n 0)
      (display str port)
      (iter port str (- n 1))]
     [else ""]))

  (call-with-output-string
    (λ (port)
      (iter port str n))))

(define* (string-pad str width char #:key (padding-direction 'left))
  (let loop ((padded-string str))
    (cond
     [(< (string-length padded-string) width)
      (cond
       [(eq? padding-direction 'left) (loop (string-append char padded-string))]
       [(eq? padding-direction 'right) (loop (string-append padded-string char))]
       [else (error "padding-direction not left or right")])]
     [else padded-string])))
